#ifndef CEVENTMANAGER_H_
#define CEVENTMANAGER_H_

#include <windows.h>
#include <deque>
#include <vector>
#include "EventDefinitions.h"

using namespace std;

class CEvent;
class IListener;

class CEventManager
{
private:

	//constructor
	CEventManager();
	//trilogy of evil
	CEventManager(const CEventManager&);
	//copy constructor
	CEventManager& operator =(const CEventManager&);
	//assigment operator
	~CEventManager(){}
	//destructor

	struct EventReg
	{
		IListener* m_pObject;
		EVENT_TYPE m_sEvent;
	};

private:

	//Local vectors to be send inside same threads
	deque<CEvent*>					m_vEventsLocalUpdate;
	deque<CEvent*>					m_vEventsLocalRender;
	
	//Vectors being fill to be send across threads
	deque<CEvent*>					m_vEventsFillUpdate;
	deque<CEvent*>					m_vEventsFillRender;
	
	//Vectors used to register the class of iListeners
	deque<EventReg> m_vRegisterInUpdateThread;
	deque<EventReg> m_vRegisterInRenderThread;
	
	////////////////////////////////////////////
	// Render Mail Box
	////////////////////////////////////////////
	deque<CEvent*>					m_vCentralEventUpdate;
	CRITICAL_SECTION				m_CritUpdateDeque;
	////////////////////////////////////////////

	////////////////////////////////////////////
	// Update Mail Box
	////////////////////////////////////////////
	deque<CEvent*>					m_vCentralEventRender; 
	CRITICAL_SECTION				m_CritRenderDeque;
	////////////////////////////////////////////

	//Helper Functions
	void SendEventUpdate(CEvent* pEvent);
	void SendEventRender(CEvent* pEvent);

	//Shutdown functionality 
	volatile bool					m_bShutdown;
	volatile bool					m_bClearFillUpdate;
	volatile bool					m_bClearFillRender;
	void ShutdownEventUpdate();
	void ShutdownEventRender();


public:
	void Initialize();

	static CEventManager* GetInstance()
	{
		static CEventManager instance;
		return &instance;
	}

	void RegisterForEventInUpdate(EVENT_TYPE sEventName, IListener* pRegisteredObject);
	void RegisterForEventInRender(EVENT_TYPE sEventName, IListener* pRegisteredObject);
	
	void UnregisterForEventInUpdate(EVENT_TYPE sEventName, IListener* pRegisteredObject);
	void UnregisterForEventInRender(EVENT_TYPE sEventName, IListener* pRegisteredObject);
	
	void UnregisterListenerAllUpdate(IListener* pListener);
	void UnregisterListenerAllRender(IListener* pListener);

	void SendEventUpdateLocal(EVENT_TYPE eventID, TBaseEventData* pData = NULL, unsigned int unSizeofData = 0);
	void SendEventRenderLocal(EVENT_TYPE eventID, TBaseEventData* pData = NULL, unsigned int unSizeofData = 0);
	void SendEventUpdateCrossToRender(EVENT_TYPE eventID, TBaseEventData* pData = NULL, unsigned int unSizeofData = 0);
	void SendEventRenderCrossToUpdate(EVENT_TYPE eventID, TBaseEventData* pData = NULL, unsigned int unSizeofData = 0);	
	
	void ProcessEventsUpdate();
	void ProcessEventsRender();

	void ClearLocalEventsUpdate();
	void ClearFillEventsUpdate();
	void ClearCentralEventsUpdate();
	void ClearLocalEventsRender();
	void ClearFillEventsRender();
	void ClearCentralEventsRender();

	void ShutdownEventManager();

	void TransfertoRenderLocal();
	void TransfertoUpdateLocal();
	void TransfertoRenderCentral();
	void TransfertoUpdateCentral();

	void SetClearFillRender(bool bValue){m_bClearFillRender = bValue;}
	void SetClearFillUpdate(bool bValue){m_bClearFillUpdate = bValue;}


};

#endif